 package com.conan.dailyflickr.app;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.SoftReference;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.HashMap;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.app.WallpaperManager;
import android.content.ContentValues;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.widget.RemoteViews;

public class BitmapManager {
	public interface ImageDownloadListener{
		public void completed(boolean largesize); 
		public void doownloadCompleted();
	}
	
	private static final String TAG = "BitmapManager";
	private final HashMap<String, SoftReference<Bitmap>> bitmapMap;
	private ArrayList<String> mPrepareGetUrl = new ArrayList<String>();
	private ImageDownloadListener mListener;
	private boolean autoUpdate = true;
	private String urlMainID = "";
	
	public BitmapManager(ImageDownloadListener listener){
		bitmapMap = new HashMap<String, SoftReference<Bitmap>>();
		mListener = listener;
		startThread();
	}
	
	public void clearBitmapItem(String urlString){
		mPrepareGetUrl.remove(urlString);
		SoftReference<Bitmap> bitmapRef = bitmapMap.remove(urlString);
		if(bitmapRef != null){
			Bitmap bitmap = bitmapRef.get();
			if(bitmap != null){
				bitmap.recycle();
				bitmap = null;
			}
		}
	}
	
	public void clearRequestBitmap(){
		mPrepareGetUrl.clear();
	}
	
	public void clearAllBitmap(){
		mPrepareGetUrl.clear();
		Bitmap main = null;
		SoftReference<Bitmap> bitmapRef = null;
		
		for(String urlString: bitmapMap.keySet()){
			bitmapRef = bitmapMap.remove(urlString);			
			Bitmap bitmap = bitmapRef.get();
			if(bitmap != null){
				if(urlString.compareToIgnoreCase(urlMainID) != 0){
					bitmap.recycle();
					bitmap = null;
				}else{
					main = bitmap;
				}
			}
		}
		
		bitmapMap.clear();
		if(main != null){
			bitmapRef = new SoftReference<Bitmap>(main);
			bitmapMap.put(urlMainID, bitmapRef);
		}
	}
	
	
	private Bitmap fetchBitmap(String urlString){
		SoftReference<Bitmap> bitmapRef = bitmapMap.get(urlString);
		if(bitmapRef != null){
			Bitmap bitmap = bitmapRef.get();
			if(bitmap != null){
				return bitmap;
			}
			// reference has expired so remove the key from drawabebitmap
			bitmapMap.remove(urlString);
		}
		
		Log.d(TAG, " image url: " + urlString);
		try{
			InputStream is = fetch(urlString);
			// TODO: save to sdcard later
			//saveToSdcard();
		
			Bitmap bitmap = BitmapFactory.decodeStream(is);
			bitmapRef = new SoftReference<Bitmap>(bitmap);
			bitmapMap.put(urlString, bitmapRef);
	        Log.d(TAG, "got a thumbnail drawable: " );
	        return bitmap;
	    } catch (MalformedURLException e) {
	        Log.e(TAG, "fetchBtimap failed", e);
	        return null;
	    } catch (IOException e) {
	        Log.e(TAG, "fetchBitmap failed", e);
	        return null;
	    }
	}
	
	
	public int getSize(){
		return bitmapMap.keySet().size();
	}

	public boolean fetchAvaiableBitmap(String urlString,  final RemoteViews views, final int viewId){
		SoftReference<Bitmap> bitmapRef = bitmapMap.get(urlString);
		if (bitmapRef != null) {
			Bitmap bitmap = bitmapRef.get();
			if (bitmap != null) {
				views.setImageViewBitmap(viewId, bitmap);
				return true;
			}
			 // Log.i(PhotoDailyInfo.TAG, "[fetchAvaiableBitmap] ===== " );
			// Reference has expired so remove the key from drawableMap			 
			bitmapMap.remove(urlString);
			
			addUrlDownload(urlString);
		}
		return false;
	}
	
	public boolean checkAvaiableBitmap(String urlString){
		return bitmapMap.containsKey(urlString);
	}
	
	private static InputStream fetch(String urlString) throws MalformedURLException, IOException{
		DefaultHttpClient httpClient = new DefaultHttpClient();
		HttpGet request = new HttpGet(urlString);
		HttpResponse response = httpClient.execute(request);
		return response.getEntity().getContent();
	}
	
	
	public void fetchBitmapOnThread(final String urlString, int position) {
		SoftReference<Bitmap> bitmapRef = bitmapMap.get(urlString);
		if(bitmapRef != null){
			Bitmap bitmap = bitmapRef.get();
			if (bitmap != null) {
				mListener.completed(false);
				return;
			}
			// Reference has expired so remove the key from drawableMap
			bitmapMap.remove(urlString);

		}
		
		if(position < 0){
			urlMainID = urlString;
			addFirstUrlDownload(urlString);
		}else{
			addUrlDownload(urlString);
		}
	}
    
	private void addFirstUrlDownload(String urlString){
		if(mPrepareGetUrl.contains(urlString)) return;
    	synchronized (mPrepareGetUrl) {    		
			mPrepareGetUrl.add(0, urlString);
			
			mPrepareGetUrl.notifyAll();
		}
	}
	
	private void addUrlDownload(String urlString){
		if(mPrepareGetUrl.contains(urlString)) return;		
    	synchronized (mPrepareGetUrl) {    		
			mPrepareGetUrl.add(urlString);
			
			mPrepareGetUrl.notifyAll();
		}
	}
    
    ImageDowloadThread getImageThread; 

	public void startThread(){
		if(getImageThread == null){
			getImageThread = new ImageDowloadThread();
			getImageThread.setName("download_thumb");
			getImageThread.start();
		}
	}

	public void stopThread(){		
		if(getImageThread != null){
			Thread t = getImageThread;
			try {
				t.join();				
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			t = null;
		}
	}

	class ImageDowloadThread extends Thread{
        @Override
        public void run() {
        	while(true){        			
    			while(!mPrepareGetUrl.isEmpty() && autoUpdate){    			
    				//TODO : set imageView to a "pending" image
    				
    				String url = mPrepareGetUrl.remove(0);
    				Bitmap bitmap = fetchBitmap(url);
    				if( bitmap!= null ){
    					// Message message = handler.obtainMessage(1, bitmap);
    					// handler.sendMessage(message);
    					mListener.completed(false);
    					Log.d(PhotoDailyInfo.TAG, "[ImageDowloadThread] done = " + mPrepareGetUrl.size() + " - " + url);
    					//autoUpdate = false;
    					// Runtime.getRuntime().freeMemory(); 
    				}else{
    					mPrepareGetUrl.add(url);
    					Log.d(PhotoDailyInfo.TAG, "[ImageDowloadThread] fail" + " - " + url);
    				}
    				
    			}
    			synchronized (mPrepareGetUrl) {		
        			try {
        				mPrepareGetUrl.wait();
        			} catch (InterruptedException e) {
        				// TODO Auto-generated catch block
        				e.printStackTrace();
        			}
        		}
        	}

        }
	};	
	
	public static boolean downloadBitmap(Context context, String urlString, String title, boolean isWallpaper){
		// replace small to large
		String pattern = "_m.jpg";
		String newPattern = "_b.jpg";
		
		urlString = urlString.replaceAll(pattern, newPattern);
		InputStream is;
		try {
			is = fetch(urlString);
		} catch (MalformedURLException e) {			
			e.printStackTrace();
			return false;
		} catch (IOException e) {			
			e.printStackTrace();
			return false;
		}
		// TODO: save to sdcard later
		//saveToSdcard();
	
		Bitmap bitmap = BitmapFactory.decodeStream(is);
      
        if(bitmap == null) return false;
        
        if(isWallpaper){
        	try {
        		WallpaperManager wallpaperManager = WallpaperManager.getInstance(context);
				wallpaperManager.setBitmap(bitmap);
			} catch (IOException e) {				
				e.printStackTrace();
				return false;
			}

        }else{
        	String name = urlString.substring(urlString.lastIndexOf("/"));
        	saveToSDCard(context, bitmap, name, title);
        }
        
		return true;
	}
	
	private static void saveToSDCard(Context context, Bitmap bitmap, String name, String title) {
	    boolean mExternalStorageAvailable = false;
	    boolean mExternalStorageWriteable = false;
	    String state = Environment.getExternalStorageState();
	    if (Environment.MEDIA_MOUNTED.equals(state)) {
	        mExternalStorageAvailable = mExternalStorageWriteable = true;
	        Log.v(TAG, "SD Card is available for read and write "
	                + mExternalStorageAvailable + mExternalStorageWriteable);
	        saveFile(context, bitmap, name, title);
	    } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
	        mExternalStorageAvailable = true;
	        mExternalStorageWriteable = false;
	        Log.v(TAG, "SD Card is available for read "
	                + mExternalStorageAvailable);
	    } else {
	        mExternalStorageAvailable = mExternalStorageWriteable = false;
	        Log.v(TAG, "Please insert a SD Card to save your Video "
	                + mExternalStorageAvailable + mExternalStorageWriteable);
	    }
	}

	private static void saveFile(Context context, Bitmap bitmap, String fullname, String title) {
	    ContentValues values = new ContentValues();
	    File SDCardRoot = Environment.getExternalStorageDirectory();
	    File SDCardDownload = new File(SDCardRoot, "download");
	     
	    
	    File outputFile = new File(SDCardDownload, fullname);
	    values.put(MediaStore.MediaColumns.DATA, outputFile.toString());
	    // values.put(MediaStore.MediaColumns.TITLE, title);
	    values.put(MediaStore.MediaColumns.DATE_ADDED, System
	            .currentTimeMillis());
	    values.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg");
	    Uri uri = context.getContentResolver().insert(
	            android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
	            values);;

	    try {
	        OutputStream outStream = context.getContentResolver()
	                .openOutputStream(uri);
	        bitmap.compress(Bitmap.CompressFormat.JPEG, 95, outStream);

	        outStream.flush();
	        outStream.close();
	    } catch (FileNotFoundException e) {
	        e.printStackTrace();
	    } catch (IOException e) {
	        e.printStackTrace();
	    }
	    bitmap.recycle();
	}

}